Imports Newtonsoft.Json

Namespace Helpers
    ''' <summary>
    ''' Una coleccion que se completa con los filtros que se pasan desde el cliente.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class FiltroColeccion
        Inherits System.Collections.Generic.List(Of Filtro)

        ''' <summary>
        ''' Devuelve una instancia de FiltroColeccion desde un string.
        ''' </summary>
        ''' <param name="Filtro">String en formato json que se va a convertir a FiltroColeccion.</param>
        ''' <returns>FiltroColeccion que se instancia desde el string.</returns>
        ''' <remarks></remarks>
        Public Shared Function Parse(Filtro As String) As FiltroColeccion
            If Not String.IsNullOrWhiteSpace(Filtro) Then
                Dim cFiltro As New FiltroColeccion
                Return Newtonsoft.Json.JsonConvert.DeserializeAnonymousType(Of FiltroColeccion)(Filtro, cFiltro)
            End If
            Return New FiltroColeccion
        End Function

        ''' <summary>
        ''' Para poder buscar un filtro en base al nombre.
        ''' </summary>
        ''' <param name="Key">Nombre del filtro a buscar.</param>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Default Public Overloads ReadOnly Property Item(ByVal Key As String) As Filtro
            Get
                For Each fi As Filtro In Me
                    If fi.Propiedad.Equals(Key) Then
                        Return fi
                    End If
                Next

                Return New Filtro
            End Get
        End Property

        ''' <summary>
        ''' Devuelve un string en representacion sql para poder aplicarlo a la query.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function ToSQL() As String
            Dim sb As New Text.StringBuilder
            For Each item As Filtro In Me
                If Not String.IsNullOrWhiteSpace(item.Valor) Then
                    sb.Append(item.ToSQL() & " " & item.Operador & " ")
                End If
            Next
            Return sb.ToString().TrimEnd("AND ".ToCharArray()).TrimEnd("OR ".ToCharArray())
        End Function

        ''' <summary>
        ''' Item Filtro se utilizan como parte de la coleccion FiltroColeccion.
        ''' </summary>
        ''' <remarks></remarks>
        Public Class Filtro
            ''' <summary>
            ''' Define el tipo de filtro que se va a utilizar.
            ''' </summary>
            ''' <remarks></remarks>
            <Newtonsoft.Json.JsonProperty("type")> _
            Public Property Tipo As String
            ''' <summary>
            ''' Propiedad sobre la cual se va a aplicar el filtro.
            ''' </summary>
            ''' <remarks></remarks>
            <Newtonsoft.Json.JsonProperty("field")> _
            Public Property Propiedad As String
            ''' <summary>
            ''' Tipo de comparacion que se va a aplicar al campo.
            ''' </summary>
            ''' <remarks></remarks>
            <Newtonsoft.Json.JsonProperty("comparison")> _
            Public Property Comparacion As String = "like"
            ''' <summary>
            ''' Valor que se va a utilizar en el filtro.
            ''' </summary>
            ''' <remarks></remarks>
            Private _Value As String
            <Newtonsoft.Json.JsonProperty("value")> _
            Public Property Valor As String
                Get
                    Return _Value
                End Get
                Set(value As String)
                    If Not String.IsNullOrWhiteSpace(value) Then
                        _Value = value
                    End If
                End Set
            End Property

            ''' <summary>
            ''' Operador con el que se van a unir las comparaciones.
            ''' </summary>
            ''' <remarks></remarks>
            Private _Operador As String = "AND"
            <Newtonsoft.Json.JsonProperty("operator")> _
            Public Property Operador As String
                Get
                    Return _Operador
                End Get
                Set(value As String)
                    If Not String.IsNullOrWhiteSpace(value) Then
                        _Operador = value
                    End If
                End Set
            End Property

            ''' <summary>
            ''' Devuelve un string en formato SQL para poder ser utilizado en la condicion de la query.
            ''' </summary>
            ''' <remarks></remarks>
            Public Function ToSQL() As String
                Select Case Tipo.ToLowerInvariant()
                    Case "list"
                        Return String.Format("{0} in ('{1}')", Propiedad, Valor.Replace("'", "''").Replace(",", "','"))
                    Case "boolean"
                        Return String.Format("{0} = {1}", Propiedad, IIf(Valor.ToLowerInvariant().Equals("true"), 1, 0))
                End Select

                If Comparacion = "like" Then
                    Return String.Format("{0} like '%{1}%'", Propiedad, Valor.Replace("'", "''"))
                End If

                If Comparacion = "lt" Then
                    If Tipo.ToLowerInvariant() = "string" Then
                        Return String.Format("{0} >= '{1}'", Propiedad, Valor.Replace("'", "''"))
                    End If
                    If Tipo.ToLowerInvariant() = "date" Then
                        Return String.Format("{0} <= '{1}'", Propiedad, DateTime.Parse(Valor).ToString("yyyy-MM-dd 23:59:59"))
                    End If
                    Return String.Format("{0} >= {1}", Propiedad, Valor.Replace("'", "''"))
                End If

                If Comparacion = "gt" Then
                    If Tipo.ToLowerInvariant() = "string" Then
                        Return String.Format("{0} <= '{1}'", Propiedad, Valor.Replace("'", "''"))
                    End If
                    If Tipo.ToLowerInvariant() = "date" Then
                        Return String.Format("{0} >= '{1}'", Propiedad, DateTime.Parse(Valor).ToString("yyyy-MM-dd 00:00:00"))
                    End If
                    Return String.Format("{0} <= {1}", Propiedad, Valor.Replace("'", "''"))
                End If

                If Comparacion = "eq" Then
                    If Valor.ToLower().Equals("null") Then
                        Return String.Format("{0} is null", Propiedad)
                    End If
                    Return String.Format("{0} = '{1}'", Propiedad, Valor.Replace("'", "''"))
                End If
                Return String.Empty
            End Function
        End Class

        Public Function ToJSON() As String
            Return JsonConvert.SerializeObject(Me)
        End Function

        Public Sub AgregarEQFilter(Campo As String, valor As String)
            Me.Add(New FiltroColeccion.Filtro() With {.Tipo = "numeric", .Comparacion = "eq", .Propiedad = Campo, .Valor = valor})
        End Sub
    End Class
End Namespace